// worker.js
function magnitude(cartesian) {
  let n = cartesian.x * cartesian.x + cartesian.y * cartesian.y + cartesian.z * cartesian.z;

  return Math.sqrt(n);
}

function distance(p1, p2) {
  let x = p1.x - p2.x;
  let y = p1.y - p2.y;
  let z = p1.z - p2.z;
  return Math.sqrt(x * x + y * y + z * z);
}

function defined(a) {
  if (a === null || a === undefined) {
    return false;
  }
  return true;
}

function subtract(left, right) {
  let result = {};
  result.x = left.x - right.x;
  result.y = left.y - right.y;
  result.z = left.z - right.z;
  return result;
}

function normalize(cartesian) {
  let result = {};
  let n = magnitude(cartesian);
  result.x = cartesian.x / n;
  result.y = cartesian.y / n;
  result.z = cartesian.z / n;

  return result;
}

function multiplyByScalar(cartesian, scalar) {
  let result = {};
  result.x = cartesian.x * scalar;
  result.y = cartesian.y * scalar;
  result.z = cartesian.z * scalar;
  return result;
}

function add(left, right) {
  let result = {};
  result.x = left.x + right.x;
  result.y = left.y + right.y;
  result.z = left.z + right.z;
  return result;
}

function cart3Equals(left, right, precision) {
  precision = precision || 0;
  var dx = Math.abs(left.x - right.x);
  var dy = Math.abs(left.y - right.y);
  var dz = Math.abs(left.z - right.z);
  return dx <= precision && dy <= precision && dz <= precision;
}

//计算到每个路径点处的路径长度和路径总长度
function computePerSegLength(ptArray) {
  let totalLength = 0;
  let result = [];
  result.push({ curLen: 0, pt: ptArray[0] });

  for (let i = 1; i < ptArray.length; ++i) {
    let curLen = distance(ptArray[i], ptArray[i - 1]);
    totalLength += curLen;
    result.push({ curLen: totalLength, pt: ptArray[i] });
  }

  result.totalLength = totalLength;
  return result;
}

function splitPath(allPath, options) {
  let finalPath = [];
  let lastSpeed = options.lastSpeed || 0;
  for (let i = 0; i < allPath.length; ++i) {
    let curStatus = allPath[i].status;
    let curPosArray = allPath[i].ptArray;
    let curStartTime = allPath[i].startTime;
    let curEndTime = allPath[i].endTime;
    let lengthInfo = computePerSegLength(curPosArray);
    let totalLength = lengthInfo.totalLength;
    let curTotalTime = curEndTime - curStartTime;

    if (curStatus === 0) {
      finalPath.push(allPath[i]);
      if (curTotalTime !== 0) {
        lastSpeed = totalLength / curTotalTime;
      }
      continue;
    }

    if (!defined(allPath[i].a) || !defined(allPath[i].limitSpeed)) {
      finalPath.push(allPath[i]);
      if (curTotalTime !== 0) {
        let a = ((totalLength - lastSpeed * curTotalTime) * 2) / curTotalTime / curTotalTime;
        lastSpeed = lastSpeed + a * curTotalTime;
      }
      continue;
    }

    let limitSpeed = Number(allPath[i].limitSpeed);
    let a = Number(allPath[i].a);
    let errorTime = 3;
    let tSpeedDown = (totalLength - curTotalTime * limitSpeed) / (0.5 * (lastSpeed - limitSpeed));
    if (tSpeedDown > 0 && tSpeedDown <= curTotalTime) {
      let realA = (limitSpeed - lastSpeed) / tSpeedDown;

      // let msg = '手动矫正加速度a,';
      // if (options.id) {
      //   msg = 'id=' + options.id + msg;
      // }
      // console.log(msg + 'startTime=' + allPath[i].startTime + ',endTime=' + allPath[i].endTime);
      // console.log("原始a=" + a + "，矫正后a=" + realA);

      a = realA;
      errorTime = 0;
    }

    let t1 = (limitSpeed - lastSpeed) / a;
    let t2 = Math.max(0, curTotalTime - t1);
    if (t2 > errorTime) {
      //拆两段
      let d1 = lastSpeed * t1 + 0.5 * a * t1 * t1;
      if (d1 < totalLength && d1 > 0) {
        //真正拆两段
        let leftLen = totalLength - d1;
        lastSpeed = leftLen / t2;
        if (Math.abs(limitSpeed * t2 - leftLen) > 1) {
          console.log('匀速阶段limitSpeed无效');
        }

        let pt1Array = [];
        let pt2Array = [];
        let bOK = false;
        for (let k = 0; k < lengthInfo.length; ++k) {
          if (lengthInfo[k].curLen < d1) {
            pt1Array.push(lengthInfo[k].pt);
          } else {
            if (!bOK) {
              bOK = true;
              //这段路拆两半
              let dir = subtract(lengthInfo[k].pt, lengthInfo[k - 1].pt);
              dir = normalize(dir);
              let preLen = d1 - lengthInfo[k - 1].curLen;
              let nextLen = lengthInfo[k].curLen - d1;
              let addPt = multiplyByScalar(dir, preLen);
              addPt = add(lengthInfo[k - 1].pt, addPt);

              pt1Array.push(addPt);
              pt2Array.push(addPt);
              pt2Array.push(lengthInfo[k].pt);
            } else {
              pt2Array.push(lengthInfo[k].pt);
            }
          }
        }

        let seg1 = {
          angleWithX: allPath[i].angleWithX,
          startTime: allPath[i].startTime,
          endTime: allPath[i].startTime + t1,
          status: allPath[i].status,
          ptArray: pt1Array,
        };
        let seg2 = {
          angleWithX: allPath[i].angleWithX,
          startTime: allPath[i].startTime + t1,
          endTime: allPath[i].endTime,
          status: 0,
          ptArray: pt2Array,
        };

        finalPath.push(seg1);
        finalPath.push(seg2);
      } else {
        //limitSpeed作为末速度反算初速度和加速度
        let v0 = (2 * totalLength) / curTotalTime - limitSpeed;
        let curA = (limitSpeed - v0) / curTotalTime;
        let len = v0 * curTotalTime + 0.5 * curA * curTotalTime * curTotalTime;
        allPath[i].beginSpeed = v0;
        finalPath.push(allPath[i]);
        lastSpeed = limitSpeed;

        //还是不能拆
        // finalPath.push(allPath[i]);
        // if (curTotalTime !== 0) {
        //   let a1 = ((totalLength - lastSpeed * curTotalTime) * 2) / curTotalTime / curTotalTime;
        //   lastSpeed = lastSpeed + a1 * curTotalTime;
        // }
      }
    } else {
      //不拆
      finalPath.push(allPath[i]);
      if (curTotalTime !== 0) {
        let a1 = ((totalLength - lastSpeed * curTotalTime) * 2) / curTotalTime / curTotalTime;
        let realLastSpeed = lastSpeed + a1 * curTotalTime;
        if (realLastSpeed <= 0) {
          let msg = '';
          if (options.id) {
            msg = 'id=' + options.id;
          }

          msg = msg + '在时间段startTime=' + allPath[i].startTime + ',endTime=' + allPath[i].endTime + '运行异常';
          console.log(msg);
          console.log('当前路段减速到' + limitSpeed + '需要' + t1 + '秒,实际运行总共' + curTotalTime + '秒,无法完成预期减速');
          console.log('按照当前路段总路程总时间和初速度实际求得终止速度为' + realLastSpeed);
          console.log('完毕');
          lastSpeed = 0;
        } else {
          lastSpeed = realLastSpeed;
        }
      }
    }
  }

  return finalPath;
}

/**
 * 根据路径信息创建采样运动实体总路径信息  返回值可直接用于attributeToEntity函数
 * @param {Array} allPath 路径信息数组
 * @param {Date} startTime 总的起始时间
 * @param {Object} [options] 可选参数
 * @param {Number} [options.step=1] 插值时每两个插值点之间的间隔时间
 * @param {Number} [options.minTimeInterval=10] 当上段末尾和本段开头路径点相同，时间差在该阈值范围内时，认为没有停顿
 * @returns {Object} 路径信息对象
 * eg:
 * let seg1 = {
        angleWithX:180, //这段路车头朝向和X轴正方向夹角，可不传
        ptArray:[p0,p1],  //路径点组 cart3类型
        startTime:5, //相对于动画总的起始时间startTime  当前路径的起始时间  单位秒
        endTime:10,//相对于动画总的起始时间startTime  当前路径的结束时间  单位秒
        status:0 //加速状态  -1/0/1分别代表匀减速 匀速 匀加速
    };
    let seg2 = {
        angleWithX:180,
        ptArray:[p1,p2],
        startTime:10,
        endTime:15,
        status:0
    };

    allPath = [seg1,seg2];
    drawControl.attributeToEntity(attr,computeMovingModelPosInfo(allPath,new Date(2023,11,25,8,30,0)))
 */
function computeMovingModelPosInfo(allPath, startTime, options) {
  options = options || {};
  let step = options.step || 1;
  let minTimeInterval = options.minTimeInterval || 10;
  options.minAdjustHeightLength = options.minAdjustHeightLength || 0.1;
  options.adjustHeight = options.adjustHeight || true;

  if (options.adjustHeight) {
    let prePathEndPos;
    for (let i = 0; i < allPath.length; ++i) {
      let curFirstPos = allPath[i].ptArray[0];
      if (prePathEndPos && distance(prePathEndPos, curFirstPos) <= options.minAdjustHeightLength) {
        allPath[i].ptArray[0].x = prePathEndPos.x;
        allPath[i].ptArray[0].y = prePathEndPos.y;
        allPath[i].ptArray[0].z = prePathEndPos.z;
      }

      prePathEndPos = allPath[i].ptArray[allPath[i].ptArray.length - 1];
    }
  }

  // let path = [allPath[0]];
  // for (let i = 1; i < allPath.length; ++i) {
  //   let curPath = allPath[i];
  //   let prePath = path[path.length - 1];
  //   let sameAngle = curPath.angleWithX === prePath.angleWithX;
  //   let sameStatus = curPath.status === prePath.status && curPath.status !== 0;
  //   let sameTime = Math.abs(curPath.startTime - prePath.endTime) < minTimeInterval;
  //   let samePos = cart3Equals(prePath.ptArray[prePath.ptArray.length - 1], curPath.ptArray[0], 0.001);
  //   if (sameAngle && sameTime && samePos && sameStatus) {
  //     //路径合并
  //     prePath.endTime = curPath.endTime;
  //     for (let j = 0; j < curPath.ptArray.length; ++j) {
  //       if (!cart3Equals(prePath.ptArray[prePath.ptArray.length - 1], curPath.ptArray[j], 0.001)) {
  //         prePath.ptArray.push(curPath.ptArray[j]);
  //       }
  //     }
  //   } else {
  //     path.push(curPath);
  //   }
  // }

  let path = splitPath(allPath, options);
  let timeArray = [];
  let posArray = [];
  let angleArray = [];

  let lastSpeed = options.lastSpeed || 0;
  let lastEndTime;
  let lastEndPos;
  for (let i = 0; i < path.length; ++i) {
    let curAngle = path[i].angleWithX;
    let curStatus = path[i].status;
    let curPosArray = path[i].ptArray;
    let curStartTime = path[i].startTime;
    let curEndTime = path[i].endTime;
    let curTotalTime = curEndTime - curStartTime;
    if (curTotalTime === 0) {
      continue;
    }

    if (defined(path[i].beginSpeed)) {
      lastSpeed = path[i].beginSpeed;
    }

    let lengthInfo = computePerSegLength(curPosArray);
    let totalLength = lengthInfo.totalLength;
    let curStartDate = new Date(startTime.getTime() + curStartTime * 1000);

    if (totalLength < 0.001) {
      timeArray.push(curStartDate);
      posArray.push(curPosArray[0]);
      angleArray.push(curAngle);

      timeArray.push(new Date(startTime.getTime() + curEndTime * 1000));
      posArray.push(curPosArray[0]);
      angleArray.push(curAngle);
      continue;
    }

    let bStay = false;
    if (
      defined(lastEndTime) &&
      defined(lastEndPos) &&
      cart3Equals(lastEndPos, curPosArray[0], 0.1) &&
      Math.abs(curStartTime - lastEndTime) >= minTimeInterval
    ) {
      //在lastEndPos驻留
      lastSpeed = 0;
      bStay = true;
    }

    lastEndTime = curEndTime;
    lastEndPos = curPosArray[curPosArray.length - 1];

    timeArray.push(curStartDate);
    posArray.push(lengthInfo[0].pt);
    angleArray.push(curAngle);
    // if (bStay && angleArray.length) {
    //   angleArray.push(angleArray[angleArray.length - 1]);
    // } else {
    //   angleArray.push(curAngle);
    // }

    if (curStatus === 0) {
      for (let j = 1; j < lengthInfo.length; ++j) {
        let curPt = lengthInfo[j].pt;
        let curLen = lengthInfo[j].curLen;
        let ptTime = (curLen / totalLength) * curTotalTime;

        let curDate = new Date(curStartDate.getTime() + ptTime * 1000);
        timeArray.push(curDate);
        posArray.push(curPt);

        angleArray.push(curAngle);
      }

      lastSpeed = totalLength / curTotalTime;
    } else {
      let a = ((totalLength - lastSpeed * curTotalTime) * 2) / curTotalTime / curTotalTime;
      for (let j = 1; j < lengthInfo.length; ++j) {
        let curPt = lengthInfo[j].pt;
        let curLen = lengthInfo[j].curLen;
        let preLen = lengthInfo[j - 1].curLen;
        // let curPtTime = (-lastSpeed + Math.sqrt(lastSpeed * lastSpeed + 2 * a * curLen)) / a;
        // let prePtTime = (-lastSpeed + Math.sqrt(lastSpeed * lastSpeed + 2 * a * preLen)) / a;

        let curPtTime = -1;
        let prePtTime = -1;
        //计算curPtTime
        if (lastSpeed * lastSpeed + 2 * a * curLen < 0) {
          console.error('参数错误 方程无解');
        } else if (lastSpeed * lastSpeed + 2 * a * curLen === 0) {
          //一个解
          curPtTime = -lastSpeed / a;
        } else {
          //两个解
          let t1 = (-lastSpeed + Math.sqrt(lastSpeed * lastSpeed + 2 * a * curLen)) / a;
          let t2 = (-lastSpeed - Math.sqrt(lastSpeed * lastSpeed + 2 * a * curLen)) / a;

          let vt1 = lastSpeed + a * t1;
          let vt2 = lastSpeed + a * t2;

          if (vt1 > 0 && vt2 < 0) {
            curPtTime = t1;
          } else if (vt1 < 0 && vt2 > 0) {
            curPtTime = t2;
          } else {
            let s1 = (vt1 * vt1 - lastSpeed * lastSpeed) / a / 2;
            let s2 = (vt2 * vt2 - lastSpeed * lastSpeed) / a / 2;

            if (Math.abs(s1 - curLen) > Math.abs(s2 - curLen)) {
              curPtTime = t2;
            } else {
              curPtTime = t1;
            }
          }
        }

        //计算prePtTime
        if (lastSpeed * lastSpeed + 2 * a * preLen < 0) {
          console.error('参数错误 方程无解');
        } else if (lastSpeed * lastSpeed + 2 * a * preLen === 0) {
          //一个解
          prePtTime = -lastSpeed / a;
        } else {
          //两个解
          let t1 = (-lastSpeed + Math.sqrt(lastSpeed * lastSpeed + 2 * a * preLen)) / a;
          let t2 = (-lastSpeed - Math.sqrt(lastSpeed * lastSpeed + 2 * a * preLen)) / a;

          let vt1 = lastSpeed + a * t1;
          let vt2 = lastSpeed + a * t2;

          if (vt1 > 0 && vt2 < 0) {
            prePtTime = t1;
          } else if (vt1 < 0 && vt2 > 0) {
            prePtTime = t2;
          } else {
            let s1 = (vt1 * vt1 - lastSpeed * lastSpeed) / a / 2;
            let s2 = (vt2 * vt2 - lastSpeed * lastSpeed) / a / 2;

            if (Math.abs(s1 - preLen) > Math.abs(s2 - preLen)) {
              prePtTime = t2;
            } else {
              prePtTime = t1;
            }
          }
        }

        if (curPtTime < 0 || prePtTime < 0) {
          console.log('计算时间出错');
        }

        let dt = curPtTime - prePtTime;
        if (dt / step >= 2) {
          let num = Math.floor(dt / step);
          let curStep = dt / num;
          let dir = subtract(lengthInfo[j].pt, lengthInfo[j - 1].pt);
          dir = normalize(dir);
          let basePt = lengthInfo[j - 1].pt;
          for (let k = 1; k <= num; ++k) {
            let costTime = prePtTime + k * curStep;
            let curDate = new Date(curStartDate.getTime() + costTime * 1000);
            let curLen = lastSpeed * costTime + 0.5 * a * costTime * costTime;
            let curVec = multiplyByScalar(dir, curLen - preLen);
            curVec = add(curVec, basePt);
            timeArray.push(curDate);
            posArray.push(curVec);
            angleArray.push(curAngle);
          }
        } else {
          let curDate = new Date(curStartDate.getTime() + curPtTime * 1000);
          timeArray.push(curDate);
          posArray.push(curPt);
          angleArray.push(curAngle);
        }
      }

      lastSpeed = lastSpeed + a * curTotalTime;
    }
  }

  let obj = {
    position: posArray,
    time: timeArray,
  };

  let bOK = true;
  for (let i = 0; i < angleArray.length; ++i) {
    if (!defined(angleArray[i])) {
      bOK = false;
      break;
    }
  }

  if (bOK) {
    obj.angleWithX = angleArray;
  }

  //记录末尾位置坐标，末尾时间，末尾速度
  if (!obj._lastPos) {
    obj._lastPos = {};
  }
  obj._lastPos.x = obj.position[obj.position.length - 1].x;
  obj._lastPos.y = obj.position[obj.position.length - 1].y;
  obj._lastPos.z = obj.position[obj.position.length - 1].z;
  obj._lastTime = obj.time[obj.time.length - 1];
  obj._lastSpeed = lastSpeed;
  obj._srcPathInfo = path;
  return obj;
}

self.onmessage = function (event) {
  let data = event.data; // 接收到的数据
  let result = computeMovingModelPosInfo(data.nextPath, data.startTime, data.options); // 进行你的数学运算
  result.id = data.id;
  self.postMessage(result); // 返回结果
};
